#########################################################################
# Time-stamp: <05/08/11 14:50:48 ostolop>
#########################################################################
package EP::EPC::Core::Treemap_View;

use strict;

use EP::Config;
use EP::Common;
use EP::Common::General;

use EP::EPC::Core;
use EP::EPC::Core::Component;
use EP::EPC::Core::Clustering::exp;

use EP::Visualization::Grid;
use EP::Visualization::Hooks;
use EP::Visualization::HeatmapGraphic;
use EP::Visualization::LineGraphic;
use EP::Visualization::TreeGraphic;
use EP::Visualization::TreemapGraphic;
use EP::Visualization::AnnotationGraphic;
use EP::Visualization::Collapser;

use PDL;
use PDL::NiceSlice;

our @ISA = qw ( EP::EPC::Core::Component );

sub process_component {
  my $self = shift;
  $self->{query} = shift if scalar @_ > 0;

  my ($svg_file, $width, $height) = $self->create_visualization ( $self->{src_dataset} );

  my $process_result = {
			visualization  => { type  => "image/svg+xml",
					    label => "Clustering Visualization",
					    value => "$EP::Config::h->{HTML_HREF}/$EP::Config::h->{WWW_TMP}/$svg_file" },
			visualization_width => $width,
			visualization_height => $height,
			src_dataset_id => $self->{src_dataset}->id,
			dst_dataset_id => $self->{src_dataset}->id
		       };

  $self->{CD}->{process_result} = $process_result;
  return $self->record_analysis_history ();
}

sub create_visualization {
  my $self = shift;

  $self->{session}->status ( "Running visualization ..." );

  my $dataset = $self->{src_dataset};

  my $clust_action = retrieve EP::Common::DBI::Action ( $self->{query}->param ( "current_action_id" ) );
  my $tree = $self->format_tree_clustering ( $clust_action );

  my $grid = new EP::Visualization::Grid ( 3, 3 );
  my $treemap = new EP::Visualization::TreemapGraphic ( data => $tree );
  my $treemap_panel = $treemap->get_control_panel();

  $grid->fillCellArray (
			[
			 [ $treemap, $treemap_panel ],
			]
		       );

  die "Failed to generate visualization!" if not defined $grid;

  my $svg_output = "vis.$dataset.$$.svg";
  $grid->to_svg ( toFile => "$EP::Config::h->{TMP}/$svg_output" );

  return ( $svg_output,
	   $grid->getGridWidth(),
	   $grid->getGridHeight() );
}

sub format_tree_clustering {
  my $self = shift;

  my ($clustering_action) = @_;
  my ($clustering_filename) = EP::Common::DBI::Action_Metadata->search ( { action => $clustering_action->id, name => "rows_clust" } );

	die "No hierarchical clustering chosen\n" if not defined $clustering_filename;

  my $clustering_file = $EP::Config::h->{EPNG_USRDATA_PATH} . "/" . $clustering_action->dst_dataset->folder->location . "/" . $clustering_filename->value;
  #return ($clustering_file, "$clustering_file.nc") if -e "$clustering_file.nc";

  my $tree = {};
  read_in_tree ( $tree, $clustering_file );

  $tree->{clustering_action_id} = $clustering_action->id;
  return $tree;
}

sub read_tree_data_from_file {
  my ($file) = shift;

  my @DATA;

  open ( CLUSTER, $file ) or die "Couldn't open the hierarchical clustering file $file: $!\n";
  while (<CLUSTER>) {
    next if /^\s*#/;

    # From the original clustering output
    my @data_row = split /\s+/;
    push @DATA, \@data_row;
  }
  close CLUSTER;

  return \@DATA;
}

sub read_in_tree {
  my $self = shift;
  my ( $tree_data ) = @_;

  my %LL;
  my @TREEDOWN;
  my $TREENODE = 0;

  my (@TREE_L, @TREE_R, %DIST, %SUBTREE, @ORIG_TREE);

  my $DATA;
  $DATA = read_tree_data_from_file ( $tree_data ) if -f $tree_data;
  $DATA = $tree_data if ref ( $tree_data ) eq "ARRAY";

  die "Couldn't read in tree data!" if not $DATA;

  foreach my $data_row ( @{$DATA} ) {
    # From the original clustering output
    my ( $LH, $RH, $LHS, $RHS, $D ) = @$data_row;

    $TREEDOWN[1] = [ 0, $LHS + $RHS ] if not exists $TREEDOWN[1];

    # @TREEDOWN  - how much space was reserved for subtree starting with that node
    my ( $TREENODE, $count ) = @{$TREEDOWN[$LH]};

    # $LHTREE, $RHTREE, $TREENODE -  tree-node id's on tree structure
    my $LHTREE = $TREENODE + 1;
    my $RHTREE = $TREENODE + nodes_in_subtree($LHS) + 1;

    ( $TREE_L   [$TREENODE], $TREE_R   [$TREENODE] ) = ( $LHTREE,           $RHTREE);
    ( $ORIG_TREE[$LHTREE  ], $ORIG_TREE[$RHTREE  ] ) = ( $LH,               $RH );
    ( $TREEDOWN [$LH      ], $TREEDOWN [$RH      ] ) = ( [ $LHTREE, $LHS ], [ $RHTREE, $RHS ] );

    $DIST{"$LH:$RH"}    = $D;
    $SUBTREE{"$LH:$RH"} = $TREENODE;

    # left leaf
    ( $TREE_L[$LHTREE], $TREE_R[$LHTREE] ) = ( 0, $LH ) if $LHS == 1;

    # right leaf
    ( $TREE_L[$RHTREE], $TREE_R[$RHTREE] ) = ( 0, $RH ) if $RHS == 1;
  }

  $self->{nr_leaves} = $$DATA[0][2] + $$DATA[0][3];
  $self->{TREE_L} = \@TREE_L;
  $self->{TREE_R} = \@TREE_R;
  $self->{DIST}   = \%DIST;
  $self->{SUBTREE} = \%SUBTREE;
  $self->{ORIG_TREE} = \@ORIG_TREE;

  $self->{data} = $DATA;
}

sub nodes_in_subtree {
  my ( $leaves ) = $_[0];
  return $leaves * 2 - 1;
}

sub treewalk {
  my $self = shift;
  my ($N) = @_;

  $N = 0 if not $N;

  if ( $self->{TREE_L}->[$N] == 0 ) {
    my $leaf = $self->{TREE_R}->[$N];
    return $leaf - 1;		# subtract 1 because indices should be zero-based
  }

  return ( treewalk ( $self, $self->{TREE_L}->[$N] ),
	   treewalk ( $self, $self->{TREE_R}->[$N] ) );
}

1;
